﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace OBDUDSUtils.Mongoose
{
    public struct PassthruMsg
    {
        public uint ProtocolID;//def=6(ISO15765)
        public uint RxStatus;//def:0
        public uint TxFlags;//def=0,if protocolID=6 txFlags=0x00000040 else = 0
        public uint Timestamp;
        public uint DataSize;
        public uint ExtraDataIndex;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4128)]
        public byte[] Data;
    }

    public enum RES_MONGOOSE_HEX
    {
        STATUS_NOERROR = 0x00,
        ERR_NOT_SUPPORTED = 0x01,
        ERR_INVALID_CHANNEL_ID = 0x02,
        ERR_INVALID_PROTOCOL_ID = 0x03,
        ERR_NULL_PARAMETER = 0x04,
        ERR_INVALID_IOCTL_VALUE = 0x05,
        ERR_INVALID_FLAGS = 0x06,
        ERR_FAILED = 0x07,
        ERR_DEVICE_NOT_CONNECTED = 0x08,
        ERR_TIMEOUT = 0x09,
        ERR_INVALID_MSG = 0x0A,
        ERR_INVALID_TIME_INTERVAL = 0x0B,
        ERR_EXCEEDED_LIMIT = 0x0C,
        ERR_INVALID_MSG_ID = 0x0D,
        ERR_DEVICE_IN_USE = 0x0E,
        ERR_INVALID_IOCTL_ID = 0x0F,
        ERR_BUFFER_EMPTY = 0x10,
        ERR_BUFFER_FULL = 0x11,
        ERR_BUFFER_OVERFLOW = 0x12,
        ERR_PIN_INVALID = 0x13,
        ERR_CHANNEL_IN_USE = 0x14,
        ERR_MSG_PROTOCOL_ID = 0x15,
        ERR_INVALID_FILTER_ID = 0x16,
        ERR_NO_FLOW_CONTROL = 0x17,
        ERR_NOT_UNIQUE = 0x18,
        ERR_INVALID_BAUDRATE = 0x19,
        ERR_INVALID_DEVICE_ID = 0x1A,
    }

    public enum ProtocolType
    {
        /// <summary>
        /// Mongoose VPW/CAN, SCI/CAN and GM
        /// </summary>
        J1850VPW = 1,
        /// <summary>
        /// Mongoose PWM/CAN and PWMF
        /// </summary>
        J1850PWM = 2,
        /// <summary>
        /// Mongoose ISO/CAN and MFC
        /// </summary>
        ISO9141 = 3,
        /// <summary>
        /// Mongoose ISO/CAN and MFC
        /// </summary>
        ISO14230 = 4,
        /// <summary>
        /// Mongoose all
        /// </summary>
        CAN = 5,
        /// <summary>
        /// Mongoose All
        /// </summary>
        ISO15765 = 6,
        /// <summary>
        /// Mongoose SCI/CAN
        /// </summary>
        SCI_A_ENGINE = 7,
        /// <summary>
        /// Mongoose SCI/CAN
        /// </summary>
        SCI_A_TRANS = 8,
        /// <summary>
        /// Mongoose SCI/CAN
        /// </summary>
        SCI_B_ENGINE = 9,
        /// <summary>
        /// Mongoose SCI/CAN
        /// </summary>
        SCI_B_TRANS = 10
    }

    class Mongoose
    {
        #region import extern dll
        [DllImport("MongooseProISO2")]
        private static extern int PassThruOpen(IntPtr name, ref uint deviceID);

        [DllImport("MongooseProISO2")]
        private static extern int PassThruConnect(uint DeviceID, uint ProtocolID, uint Flags, uint BaudRate, ref uint pChannelID);

        [DllImport("MongooseProISO2")]
        private static extern int PassThruDisconnect(uint ChannelID);

        [DllImport("MongooseProISO2")]
        private static extern int PassThruClose(uint DeviceID);

        [DllImport("MongooseProISO2")]
        private static extern int PassThruReadVersion(uint DeviceID, string pFirmwareVersion, string pDllVersion, string pApiVersion);

        [DllImport("MongooseProISO2")]
        public static extern int PassThruGetLastError(string pErrorDescription);

        [DllImport("MongooseProISO2")]
        private static extern int PassThruIoctl(uint HandleID, uint IoctlID, IntPtr pInput, IntPtr pOutput);

        [DllImport("MongooseProISO2")]
        private static extern int PassThruReadMsgs(uint ChannelID, ref PassthruMsg pMsg, ref uint pNumMsgs, uint Timeout);

        [DllImport("MongooseProISO2")]
        private static extern int PassThruStartMsgFilter(uint ChannelID, uint FilterType, ref PassthruMsg pMaskMsg, ref PassthruMsg pPatternMsg, ref PassthruMsg pFlowControlMsg, ref uint pMsgID);


        [DllImport("MongooseProISO2")]
        private static extern int PassThruWriteMsgs(uint ChannelID, ref PassthruMsg pMsg, ref uint pNumMsgs, uint Timeout);

        [DllImport("MongooseProISO2")]
        private static extern int PassThruStartPeriodicMsg(uint ChannelID, ref PassthruMsg pMsg, ref uint pMsgID, uint TimeInterval);

        [DllImport("MongooseProISO2")]
        private static extern int PassThruStopPeriodicMsg(uint ChannelID, uint MsgID);
        #endregion

        #region mongoose func

        private static RES_MONGOOSE_HEX GetMongooseStatus(int value)
        {
            return (RES_MONGOOSE_HEX)Enum.Parse(typeof(RES_MONGOOSE_HEX), value.ToString());
        }

        /// <summary>
        /// 初始化并连接到Cardaq
        /// </summary>
        /// <param name="name"></param>
        /// <param name="deviceID"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonOpen(IntPtr name, ref uint deviceID)
        {
            return GetMongooseStatus(PassThruOpen(name, ref deviceID));
        }

        /// <summary>
        /// 连接到车辆网络
        /// </summary>
        /// <param name="DeviceID"></param>
        /// <param name="ProtocolID"></param>
        /// <param name="Flags"></param>
        /// <param name="BaudRate"></param>
        /// <param name="pChannelID"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonConnect(uint DeviceID, uint ProtocolID, uint Flags, uint BaudRate, ref uint pChannelID)
        {
            return GetMongooseStatus(PassThruConnect(DeviceID, ProtocolID, Flags, BaudRate, ref pChannelID));
        }

        /// <summary>
        /// 断开到车辆网络
        /// </summary>
        /// <param name="ChannelID"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonDisconnect(uint ChannelID)
        {
            return GetMongooseStatus(PassThruDisconnect(ChannelID));
        }

        /// <summary>
        /// 与Cardaq的断开连接
        /// </summary>
        /// <param name="DeviceID"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonClose(uint DeviceID)
        {
            return GetMongooseStatus(PassThruClose(DeviceID));
        }

        /// <summary>
        /// 报表版本信息
        /// </summary>
        /// <param name="DeviceID"></param>
        /// <param name="pFirmwareVersion"></param>
        /// <param name="pDllVersion"></param>
        /// <param name="pApiVersion"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonReadVersion(uint DeviceID, string pFirmwareVersion, string pDllVersion, string pApiVersion)
        {
            return GetMongooseStatus(PassThruReadVersion(DeviceID, pFirmwareVersion, pDllVersion, pApiVersion));
        }

        /// <summary>
        /// 描述最近的错误
        /// </summary>
        /// <param name="pErrorDescription"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonGetLastError(string pErrorDescription)
        {
            return GetMongooseStatus(PassThruGetLastError(pErrorDescription));
        }

        /// <summary>
        /// 多重意义，传入参数内容不同，导致不同结果
        /// </summary>
        /// <param name="HandleID"></param>
        /// <param name="IoctlID"></param>
        /// <param name="pInput"></param>
        /// <param name="pOutput"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonIcotl(uint HandleID, uint IoctlID, IntPtr pInput, IntPtr pOutput)
        {
            return GetMongooseStatus(PassThruIoctl(HandleID, IoctlID, pInput, pOutput));
        }

        /// <summary>
        /// 接收网络消息
        /// </summary>
        /// <param name="ChannelID"></param>
        /// <param name="pMsg"></param>
        /// <param name="pNumMsgs"></param>
        /// <param name="Timeout"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonReadMsgs(uint ChannelID, ref PassthruMsg pMsg, ref uint pNumMsgs, uint Timeout)
        {
            return GetMongooseStatus(PassThruReadMsgs(ChannelID, ref pMsg, ref pNumMsgs, Timeout));
        }

        /// <summary>
        /// 应用网路讯息过滤器
        /// </summary>
        /// <param name="ChannelID"></param>
        /// <param name="FilterType"></param>
        /// <param name="pMaskMsg"></param>
        /// <param name="pPatternMsg"></param>
        /// <param name="pFlowControlMsg"></param>
        /// <param name="pMsgID"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonStartMsgFilter(uint ChannelID, uint FilterType, ref PassthruMsg pMaskMsg,
            ref PassthruMsg pPatternMsg, ref PassthruMsg pFlowControlMsg, ref uint pMsgID)
        {
            return GetMongooseStatus(PassThruStartMsgFilter(ChannelID, FilterType, ref pMaskMsg, ref pPatternMsg, ref pFlowControlMsg, ref pMsgID));
        }

        /// <summary>
        /// 发送网络消息
        /// </summary>
        /// <param name="ChannelID"></param>
        /// <param name="pMsg"></param>
        /// <param name="pNumMsgs">指示该通道_msg数组仅包含几条消息</param>
        /// <param name="Timeout"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonWriteMsgs(uint ChannelID, ref PassthruMsg pMsg, ref uint pNumMsgs, uint Timeout)
        {
            return GetMongooseStatus(PassThruWriteMsgs(ChannelID, ref pMsg, ref pNumMsgs, Timeout));
        }

        /// <summary>
        /// 持续传送讯息
        /// </summary>
        /// <param name="ChannelID"></param>
        /// <param name="pMsg"></param>
        /// <param name="pMsgID"></param>
        /// <param name="TimeInterval"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonStartPeriodicMsg(uint ChannelID, ref PassthruMsg pMsg, ref uint pMsgID, uint TimeInterval)
        {
            return GetMongooseStatus(PassThruStartPeriodicMsg(ChannelID, ref pMsg, ref pMsgID, TimeInterval));
        }

        /// <summary>
        /// 停止连续传送讯息
        /// </summary>
        /// <param name="ChannelID"></param>
        /// <param name="MsgID"></param>
        /// <returns></returns>
        public static RES_MONGOOSE_HEX MonStopPeriodicMsg(uint ChannelID, uint MsgID)
        {
            return GetMongooseStatus(PassThruStopPeriodicMsg(ChannelID, MsgID));
        }
        #endregion
    }
}
